﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Hprose.RPC;
using HproseRpcTester.Service;
using HproseRpcTester.Utils;

namespace HproseRpcTester.RpcClient
{
    public interface IRpcClientBase
    {
        ILog log { get; }
        Client RPC { get; }

        void SetTimeout(TimeSpan timeout);
        void Invoke(string name, params object[] args);
        void Invoke(TimeSpan timeout, string name, params object[] args);
        T Invoke<T>(TimeSpan timeout, string name, params object[] args);
        T Invoke<T>(string name, params object[] args);
        Task InvokeAsync(string name, params object[] args);
        Task<T> InvokeAsync<T>(string name, params object[] args);

        /// <summary>
        /// 不需要状态切换的请使用该方案
        /// </summary>
        /// <param name="name"></param>
        /// <param name="args"></param>
        void InvokeEmptyState(string name, params object[] args);

        /// <summary>
        /// 不需要状态切换的请使用该方案
        /// </summary>
        /// <param name="name"></param>
        /// <param name="args"></param>
        void InvokeEmptyState(TimeSpan timeout, string name, params object[] args);
    }

    public abstract class RpcClientBase : IRpcClientBase
    {
        public ILog log { get; protected set; } = new ConsoleLogger();
        public Client RPC { get; protected set; }

        /// <summary>
        /// 时序执行前调用的事件
        /// </summary>
        public event Action StartEvent;

        /// <summary>
        /// 时序执行后调用的事件
        /// </summary>
        public event Action EndEvent;
        public void SetTimeout(TimeSpan timeout) => RPC.Timeout = timeout;

        public T Invoke<T>(string name, params object[] args)
        {
            try
            {
                StartEvent?.Invoke();

                RPC.Timeout = TimeSpan.FromSeconds(AppConsts.RPCTiemOut);
                var result = RPC.Invoke<T>(name, args.ToArray());
                EndEvent?.Invoke();
                return result;
            }
            catch (Exception e)
            {
                Console.WriteLine($"Invoke<T> 1 异常：{e}");

                EndEvent?.Invoke();
                if (typeof(T) == typeof(string))
                {
                    return (T)(object)RPCMessage.TimeOut.ToJson();
                }
                else
                    return default(T);
            }
        }

        public void Invoke(string name, params object[] args)
        {
            StartEvent?.Invoke();
            RPC.Timeout = TimeSpan.FromSeconds(AppConsts.RPCTiemOut);
            RPC.Invoke(name, args.ToArray());
            EndEvent?.Invoke();
        }

        public void Invoke(TimeSpan timeout, string name, params object[] args)
        {
            StartEvent?.Invoke();
            RPC.Timeout = timeout;
            RPC.Invoke(name, args.ToArray());
            EndEvent?.Invoke();
        }

        public T Invoke<T>(TimeSpan timeout, string name, params object[] args)
        {
            try
            {
                StartEvent?.Invoke();
                RPC.Timeout = timeout;
                var result = RPC.Invoke<T>(name, args.ToArray());
                EndEvent?.Invoke();
                return result;
            }
            catch (Exception e)
            {
                Console.WriteLine($"Invoke<T> 2 异常：{e}");

                EndEvent?.Invoke();
                if (typeof(T) == typeof(string))
                {
                    return (T)(object)RPCMessage.TimeOut.ToJson();
                }
                else
                    return default(T);
            }
        }
        public Task InvokeAsync(string name, params object[] args)
        {
            StartEvent?.Invoke();
            RPC.Timeout = TimeSpan.FromSeconds(AppConsts.RPCTiemOut);
            var result = RPC.InvokeAsync(name, args.ToArray());
            EndEvent?.Invoke();
            return result;
        }

        public Task<T> InvokeAsync<T>(string name, params object[] args)
        {
            StartEvent?.Invoke();
            RPC.Timeout = TimeSpan.FromSeconds(AppConsts.RPCTiemOut);
            var result = RPC.InvokeAsync<T>(name, args.ToArray());
            EndEvent?.Invoke();
            return result;
        }

        public Task<T> InvokeAsync<T>(TimeSpan timeOut, string name, params object[] args)
        {
            StartEvent?.Invoke();
            RPC.Timeout = timeOut;
            var result = RPC.InvokeAsync<T>(name, args.ToArray());
            EndEvent?.Invoke();
            return result;
        }

        /// <summary>
        /// 非电机运行时，不更改状态，使用此方法
        /// </summary>
        /// <param name="name"></param>
        /// <param name="args"></param>
        public void InvokeEmptyState(string name, params object[] args)
        {
            RPC.Timeout = TimeSpan.FromSeconds(AppConsts.RPCTiemOut);
            RPC.Invoke(name, args.ToArray());
        }

        /// <summary>
        /// 非电机运行时，不更改状态，使用此方法
        /// </summary>
        /// <param name="name"></param>
        /// <param name="args"></param>
        public T InvokeEmptyState<T>(string name, params object[] args)
        {
            try
            {
                RPC.Timeout = TimeSpan.FromSeconds(AppConsts.RPCTiemOut);
                var result = RPC.Invoke<T>(name, args.ToArray());
                return result;
            }
            catch (Exception e)
            {
                if (typeof(T) == typeof(string))
                {
                    return (T)(object)RPCMessage.TimeOut.ToJson();
                }
                else
                    return default(T);
            }
        }
        public void InvokeEmptyState(TimeSpan timeout, string name, params object[] args)
        {
            RPC.Timeout = timeout;
            RPC.Invoke(name, args.ToArray());
        }
    }
}
